/*
 * Created by JFormDesigner on Tue Feb 07 10:19:42 CST 2023
 */

package com.dongbao.dialog;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;

import com.dongbao.entity.TreeNode;
import com.dongbao.util.TreeNodeUtil;
import com.intellij.ide.highlighter.JavaFileType;
import com.intellij.ide.util.TreeClassChooser;
import com.intellij.ide.util.TreeClassChooserFactory;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.SelectionModel;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiClassImpl;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiEditorUtil;
import com.intellij.ui.*;
import net.miginfocom.swing.*;
import org.jetbrains.annotations.NotNull;

import static com.dongbao.common.AuthorityEnum.MAIN_ANNOTIONS_NAME;

/**
 * @author admin
 */
public class BindNodeDialog extends JDialog {

    private Project myProject;

    private AnActionEvent event;

    private EditorTextField editorField;

    /**
     * 当前选择类文件弹窗所选择的类对象
     * */
    private PsiClass selected;

    /**
     * 当前打开的方法
     * */
    private PsiMethod curMethod ;

    private List<PsiMethod> psiMethods = new ArrayList<PsiMethod>();

    /**
     * 需要插入别的节点后面的节点
     * */
    private PsiElement afterElementAt;

    /**
     * 被插入节点的节点
     * */
    private PsiElement beforeElementAt;

    public BindNodeDialog(AnActionEvent event) {
        super();
        //获取当前选中的内容
        SelectionModel selectionModel = event.getRequiredData(CommonDataKeys.EDITOR).getSelectionModel();
        Pattern pattern = Pattern.compile(TreeNodeUtil.isFlowPatter, Pattern.CASE_INSENSITIVE);//创建匹配数字字符的模式
        Matcher matcher = pattern.matcher(selectionModel.getSelectedText());
        Boolean isExis = false;
        while (matcher.find())//matcher.find()用于查找是否有这个字符，有的话返回true
        {
            isExis = true;
            break;
        }
        if(null == selectionModel.getSelectedText() || !isExis){
            //弹窗提示当前未选择节点
            ValidationInfo validationInfo = new ValidationInfo("当前未选择节点,请使用鼠标划出完整节点。");
            Messages.showMessageDialog(validationInfo.message,"提示", Messages.getInformationIcon());
            return ;
        }
        //将当前选择的内容转换为PsiElement
        int leadSelectionOffset = selectionModel.getLeadSelectionOffset();
        afterElementAt = PsiEditorUtil.getPsiFile(event.getRequiredData(CommonDataKeys.EDITOR)).findElementAt(1192);

        super.setModal(true);
        this.event = event;
        this.myProject = event.getProject();
        initComponents();

        //创建监听事件
        classNameInput.addKeyListener(new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {
                // 仅支持输入数字且最多输入16位
                ProgressManager.getInstance().run(new Task.Backgroundable(myProject, event.getPresentation().getText(), false) {
                    @Override
                    public void run(@NotNull ProgressIndicator indicator) {
                        ApplicationManager.getApplication().runReadAction(
                                () -> {
//                                    doSearch(classNameInput.getText());
                                }
                        );
                    }
                });
//                System.out.println("1-----"+e.getKeyChar());
            }

            @Override
            public void keyPressed(KeyEvent e) {

            }

            @Override
            public void keyReleased(KeyEvent e) {

            }
        });

        cancelButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
//                dispose();
                setVisible(false);
            }
        });

        /* selectClassBtn 选择类点击事件 */
        selectClassBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                createClassSearch();
                //读取class中所有的方法
                renderTable();
            }
        });

        Object[][] rowData=new Object[0][];
        final Object[] columnNames = {"方法名称"};
        TableModel dataModel = new DefaultTableModel(rowData,columnNames);
        methodTab.setModel(dataModel);

        //渲染加载初试数据
        this.initCurEditClass();

        super.setVisible(true);
        super.requestFocus();
        this.setLocationRelativeTo(null);
    }

    /**
     * 打开选择类弹窗,选择类中的方法读取到列表组件中
     * */
    private void renderTable(){
        psiMethods.clear();
        if(selected!=null){
            classNameInput.setText(selected.getQualifiedName());
            //读取类中所有带有FlowChat注解的方法
            PsiMethod[] methods = selected.getMethods();
            for(PsiMethod method:methods){
                PsiAnnotation annotation = method.getAnnotation(MAIN_ANNOTIONS_NAME);
                if(annotation!=null){
                    psiMethods.add(method);
                }
            }
            //处理所有符合条件的方法
            /* 渲染错误数据展示的表格 */
            Object[][] rowData=new Object[psiMethods.size()][];
            for(int i=0;i<psiMethods.size();i++){
                PsiMethod flowMethod = psiMethods.get(i);
                rowData[i] = new Object[]{
                        flowMethod.getName()
                };
            }
            final Object[] columnNames = {"方法名称"};
            TableModel dataModel = new DefaultTableModel(rowData,columnNames);
            methodTab.setModel(dataModel);
            //允许表格内容编辑
            methodTab.setEnabled(false);
            methodTab.addMouseListener(new MouseAdapter(){
                @Override
                public void mouseClicked(MouseEvent e){
                    if(e.getClickCount() == 1){
//                       //实现双击 {
                        int row =((JTable)e.getSource()).rowAtPoint(e.getPoint()); //获得行位置
                        int  col=((JTable)e.getSource()).columnAtPoint(e.getPoint());
//                        //获得列位置
                        TableModel tbModel = methodTab.getModel();
                        Object cellVal=(String)(tbModel.getValueAt(row,col));
                        curMethod = psiMethods.stream().filter(item->{
                            return item.getName().equals((String)(tbModel.getValueAt(row,col)));
                        }).findAny().orElse(null);

                        codeEditPlan.removeAll();
                        EditorTextField myInput = new EditorTextField(curMethod.getText(), myProject, JavaFileType.INSTANCE);
                        String[] split = curMethod.getText().split("\\r\\n|\\r|\\n");
                        myInput.setMinimumSize(new Dimension(Double.hashCode(myInput.getPreferredSize().getWidth()),split.length*20));
                        codeEditPlan.setMinimumSize(new Dimension(Double.hashCode(myInput.getPreferredSize().getWidth()),split.length*20));
                        codeEditPlan.add(myInput);

                        //绑定菜单
                        bindEditMenu(myInput);

                    }
                }
            });
        }
    }

    /**
     * 刷新弹窗内容
     * */
    private void referDialogEditContent(String content,PsiMethod curMethod){
        codeEditPlan.removeAll();
        EditorTextField myInput = new EditorTextField(content, myProject, JavaFileType.INSTANCE);

        String[] split = curMethod.getText().split("\\r\\n|\\r|\\n");
        myInput.setMinimumSize(new Dimension(Double.hashCode(myInput.getPreferredSize().getWidth()),split.length*20));
        codeEditPlan.setMinimumSize(new Dimension(Double.hashCode(myInput.getPreferredSize().getWidth()),split.length*20));
        codeEditPlan.add(myInput);
    }

    /**
     * 使用当前所打开的java文件渲染弹窗中的类名、方法与方法内容
     * */
    private void initCurEditClass(){
        psiMethods.clear();
        //获取当前编辑窗口的class 并填充到class名字框
        VirtualFile virtualFile = event.getRequiredData(CommonDataKeys.VIRTUAL_FILE);
        PsiFile file = PsiManager.getInstance(myProject).findFile(virtualFile);
        //获取当前class的所有Method的方法,填充到Table中
        PsiElement[] children = file.getChildren();

        int num = 0 ;
        for(PsiElement child:children){
            if(child instanceof PsiClassImpl){
                PsiClassImpl psiClassImpl = (PsiClassImpl)child;
                this.classNameInput.setText(psiClassImpl.getQualifiedName());
                psiMethods.addAll(Arrays.asList(((PsiClassImpl) child).getMethods()));
                if(num==0 && psiMethods.size()>0){
                    referDialogEditContent(psiMethods.get(0).getText(),psiMethods.get(0));
                    num++;
                }
                selected = psiClassImpl;

            }
        }
        Object[][]  rowData = new Object[psiMethods.size()][];
        for(int i=0;i<psiMethods.size();i++){
            PsiMethod method = psiMethods.get(i);
            rowData[i] = new Object[]{
                    method.getName()
            };
        }
        //获取当前的第一个Method的方法 填充到代码的编辑窗口中
        final Object[] columnNames = {"方法名称"};

        TableModel dataModel = new DefaultTableModel(rowData,columnNames);
        methodTab.setModel(dataModel);
        methodTab.addMouseListener(new MouseAdapter(){
            @Override
            public void mouseClicked(MouseEvent e){
                if(e.getClickCount() == 1){
//                       //实现双击 {
                    int row =((JTable)e.getSource()).rowAtPoint(e.getPoint()); //获得行位置
                    int  col=((JTable)e.getSource()).columnAtPoint(e.getPoint());
//                        //获得列位置
                    TableModel tbModel = methodTab.getModel();
                    Object cellVal=(String)(tbModel.getValueAt(row,col));
                    curMethod = psiMethods.stream().filter(item->{
                        return item.getName().equals((String)(tbModel.getValueAt(row,col)));
                    }).findAny().orElse(null);

                    codeEditPlan.removeAll();
                    EditorTextField myInput = new EditorTextField(curMethod.getText(), myProject, JavaFileType.INSTANCE);
                    String[] split = curMethod.getText().split("\\r\\n|\\r|\\n");
                    myInput.setMinimumSize(new Dimension(Double.hashCode(myInput.getPreferredSize().getWidth()),split.length*20));
                    codeEditPlan.setMinimumSize(new Dimension(Double.hashCode(myInput.getPreferredSize().getWidth()),split.length*20));
                    codeEditPlan.add(myInput);

                    //绑定菜单
                    bindEditMenu(myInput);

                }
            }
        });

    }

    /**
     * 绑定右键菜单
     * */
    private void bindEditMenu(EditorTextField myInput){
        //为按钮创建一个右键菜单
        JPopupMenu pop = new JPopupMenu();
        JMenuItem item1 = new JMenuItem("绑定节点");
        item1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // Handle the user's click on "Option 1"
                System.out.println("Option 1 was clicked");
            }
        });
        item1.addMouseListener(new MouseAdapter(){
            @Override
            public void mouseReleased(MouseEvent e) {
                //获取父节点选择的内容
                SelectionModel selectionModel = myInput.getEditor().getSelectionModel();
                String selectedText = myInput.getEditor().getSelectionModel().getSelectedText().trim();
                System.out.println(selectedText);

                //获取外面IDEA编辑器窗口选择的文本
                SelectionModel parentWindowsSelect = event.getRequiredData(CommonDataKeys.EDITOR).getSelectionModel();
                System.out.println("第一窗口选择的节点：" +parentWindowsSelect.getSelectedText());
                System.out.println("第二窗口选择的节点：" + selectionModel.getSelectedText());

                //给父节点内容生成ID
                PsiFile psiFile = selected.getContainingFile();
                PsiElement parentBody = psiFile.findElementAt(curMethod.getTextOffset() + myInput.getEditor().getSelectionModel().getSelectionStart()).getParent();
                PsiElement parentElementAt = null;
                for(PsiElement childElement:parentBody.getChildren()){
                    if(childElement.getText().contains(selectedText)){
                        parentElementAt = childElement;
                        break;
                    }
                }
                //判断是否存在ID信息
                TreeNode parentNode = null;
                if(TreeNodeUtil.isExistId(parentElementAt)){
                    parentNode = TreeNodeUtil.readerDoucument(parentElementAt);
                }else{
                    parentNode = TreeNodeUtil.createId(parentElementAt);
                }
                //将创建的id对象写入到 Element 中
                TreeNodeUtil.writerDocument(parentNode,parentElementAt,event);

                //处理需要绑定的子节点信息
                Editor editor = event.getRequiredData(CommonDataKeys.EDITOR);
                PsiFile childElementFile = event.getRequiredData(CommonDataKeys.PSI_FILE);
                PsiElement childElementParent = childElementFile.findElementAt(parentWindowsSelect.getLeadSelectionOffset()).getParent();
                PsiElement childElement = null;
                for(PsiElement childElements:childElementParent.getChildren()){
                    if(childElements.getText().contains(editor.getSelectionModel().getSelectedText(). trim())){
                        childElement = childElements;
                    }
                }
//                PsiElement childElement = childElementFile.findElementAt(parentWindowsSelect.getLeadSelectionOffset());
                //判断是否存在ID信息
                TreeNode childNode = null;
                if(TreeNodeUtil.isExistId(childElement)){
                    childNode = TreeNodeUtil.readerDoucument(childElement);
                }else{
                    childNode = TreeNodeUtil.createId(childElement);
                }
                childNode.setParentId(parentNode.getId());
                TreeNodeUtil.writerDocument(childNode,childElement,event);

                setVisible(false);
            }
        });
        pop.add(item1);
        pop.show(myInput,0,0);
        myInput.getEditor().getContentComponent().setComponentPopupMenu(pop);
        myInput.setComponentPopupMenu(pop);
    }


    //打开类搜索器
    private void createClassSearch(){
        TreeClassChooserFactory factory = TreeClassChooserFactory.getInstance(myProject);
        final Module module = null;
        GlobalSearchScope scope = null;
        if (module != null) {
            scope = GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module);
        } else {
            scope = GlobalSearchScope.allScope(myProject);
        }
        PsiClass ecClass = JavaPsiFacade.getInstance(myProject).findClass("com.dongbao.per", scope);
        TreeClassChooser chooser = factory.createInheritanceClassChooser("选择类", scope, ecClass, null);
        chooser.showDialog();
        selected = chooser.getSelected();
    }



    private void initComponents() {
        // JFormDesigner - Component initialization - DO NOT MODIFY  //GEN-BEGIN:initComponents  @formatter:off
        dialogPane = new JPanel();
        contentPanel = new JPanel();
        panel1 = new JPanel();
        classNameInput = new JTextField();
        selectClassBtn = new JButton();
        scrollPane1 = new JScrollPane();
        methodTab = new JTable();
        codeScrollEditPlan = new JScrollPane();
        codeEditPlan = new JPanel();
        buttonBar = new JPanel();
        okButton = new JButton();
        cancelButton = new JButton();

        //======== this ========
        setMinimumSize(new Dimension(900, 500));
        setPreferredSize(new Dimension(900, 650));
        setTitle("\u9009\u62e9\u5173\u8054\u7236\u8282\u70b9");
        Container contentPane = getContentPane();
        contentPane.setLayout(new BorderLayout());

        //======== dialogPane ========
        {
            dialogPane.setMinimumSize(new Dimension(800, 600));
            dialogPane.setMaximumSize(null);
            dialogPane.setPreferredSize(new Dimension(900, 553));
            dialogPane.setLayout(new BorderLayout());

            //======== contentPanel ========
            {
                contentPanel.setMinimumSize(new Dimension(800, 800));
                contentPanel.setLayout(new MigLayout(
                    "insets dialog,hidemode 3",
                    // columns
                    "[fill]" +
                    "[fill]" +
                    "[fill]" +
                    "[fill]" +
                    "[fill]" +
                    "[fill]" +
                    "[fill]" +
                    "[fill]" +
                    "[fill]" +
                    "[fill]" +
                    "[fill]" +
                    "[fill]" +
                    "[fill]" +
                    "[fill]" +
                    "[fill]" +
                    "[fill]" +
                    "[fill]",
                    // rows
                    "[48]" +
                    "[48]"));

                //======== panel1 ========
                {
                    panel1.setMinimumSize(new Dimension(500, 74));
                    panel1.setLayout(new MigLayout(
                        "hidemode 3",
                        // columns
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]" +
                        "[fill]",
                        // rows
                        "[]" +
                        "[292]" +
                        "[]"));
                    panel1.add(classNameInput, "cell 0 0 18 1");

                    //---- selectClassBtn ----
                    selectClassBtn.setText("\u9009\u62e9\u7c7b");
                    panel1.add(selectClassBtn, "cell 18 0 6 1");

                    //======== scrollPane1 ========
                    {
                        scrollPane1.setViewportView(methodTab);
                    }
                    panel1.add(scrollPane1, "cell 0 1 11 1,width 200:200");

                    //======== codeScrollEditPlan ========
                    {

                        //======== codeEditPlan ========
                        {
                            codeEditPlan.setAutoscrolls(true);
                            codeEditPlan.setLayout(new MigLayout(
                                "hidemode 3",
                                // columns
                                "[fill]" +
                                "[fill]",
                                // rows
                                "[]" +
                                "[]" +
                                "[]"));
                        }
                        codeScrollEditPlan.setViewportView(codeEditPlan);
                    }
                    panel1.add(codeScrollEditPlan, "cell 12 1 13 1,width 400:400:400,height 400:400:400");
                }
                contentPanel.add(panel1, "cell 0 0 17 2");
            }
            dialogPane.add(contentPanel, BorderLayout.NORTH);

            //======== buttonBar ========
            {
                buttonBar.setLayout(new MigLayout(
                    "insets dialog,alignx right",
                    // columns
                    "[button,fill]" +
                    "[button,fill]",
                    // rows
                    null));

                //---- okButton ----
                okButton.setText("OK");
                buttonBar.add(okButton, "cell 0 0");

                //---- cancelButton ----
                cancelButton.setText("Cancel");
                buttonBar.add(cancelButton, "cell 1 0");
            }
            dialogPane.add(buttonBar, BorderLayout.SOUTH);
        }
        contentPane.add(dialogPane, BorderLayout.CENTER);
        pack();
        setLocationRelativeTo(getOwner());
        // JFormDesigner - End of component initialization  //GEN-END:initComponents  @formatter:on
    }

    // JFormDesigner - Variables declaration - DO NOT MODIFY  //GEN-BEGIN:variables  @formatter:off
    private JPanel dialogPane;
    private JPanel contentPanel;
    private JPanel panel1;
    private JTextField classNameInput;
    private JButton selectClassBtn;
    private JScrollPane scrollPane1;
    private JTable methodTab;
    private JScrollPane codeScrollEditPlan;
    private JPanel codeEditPlan;
    private JPanel buttonBar;
    private JButton okButton;
    private JButton cancelButton;
    // JFormDesigner - End of variables declaration  //GEN-END:variables  @formatter:on
}
